#include <functional>
template<bool strict, typename R>
struct compare_strict_or_reflexive;

template<typename R>
struct compare_strict_or_reflexive<true, R>
{
	bool operator()(const typename R::first_argument_type& a,
					const typename R::first_argument_type& b, R r)
	{
		return r(a, b); //strict, a < b
	}
};

template<typename R>
struct compare_strict_or_reflexive<false, R>
{
	bool operator()(const typename R::first_argument_type& a,
					const typename R::first_argument_type& b, R r)
	{
		return !r(b,a); //reflexive !b < a => a <= b
	}
};

template<int ia, int ib, typename R>
const typename R::first_argument_type& select_0_2(const typename R::first_argument_type& a,
												const typename R::first_argument_type& b, R r)
{
	compare_strict_or_reflexive<(ia < ib), R>cmp;
	if ( cmp(b,a,r) ) return b;
	return a;
}

template<int ia, int ib, int ic, int id, typename R>
const typename R::first_argument_type& 
	select_1_4_ab_cd(const typename R::first_argument_type& a,
					const typename R::first_argument_type& b,
					const typename R::first_argument_type& c,
					const typename R::first_argument_type& d,R r)
{
	compare_strict_or_reflexive<(ia < ic), R> cmp;
	if (cmp(c,a,r)) 
		return select_0_2<ia,id>(a,d,r);
	return select_0_2<ib,ic>(b,c,r);
}

template<int ia, int ib, int ic, int id, typename R>
const typename R::first_argument_type& 
	select_1_4_ab(const typename R::first_argument_type& a,
					const typename R::first_argument_type& b,
					const typename R::first_argument_type& c,
					const typename R::first_argument_type& d,R r)
{
	compare_strict_or_reflexive<(ic < id), R> cmp;
	if (cmp(d,c,r))
		return select_1_4_ab_cd<ia,ib,id,ic>(a,b,d,c,r);
	return select_1_4_ab_cd<ia,ib,ic,id>(a,b,c,d,r);
}

template<int ia, int ib, int ic, int id, typename R>
const typename R::first_argument_type& 
	select_1_4(const typename R::first_argument_type& a,
					const typename R::first_argument_type& b,
					const typename R::first_argument_type& c,
					const typename R::first_argument_type& d,R r)
{
	compare_strict_or_reflexive<(ia < ib), R> cmp;
	if (cmp(b,a,r))
		return select_1_4_ab<ib,ia,ic,id>(b,a,c,d,r);
	return select_1_4_ab<ia,ib,ic,id>(a,b,c,d,r);
}

template<int ia, int ib, int ic, int id, int ie, typename R>
const typename R::first_argument_type& 
	select_2_5_ab_cd(const typename R::first_argument_type& a,
					const typename R::first_argument_type& b,
					const typename R::first_argument_type& c,
					const typename R::first_argument_type& d,
					const typename R::first_argument_type& e,R r)
{
	compare_strict_or_reflexive<(ia < ic), R> cmp;
	if (cmp(c,a,r) ) 
		return select_1_4_ab<ia,ib,id,ie>(a,b,d,e,r); // c < a, a <= b
	return select_1_4_ab<ic,id,ib,ie>(c,d,b,e,r); // a <=c , c <= d
}

template<int ia, int ib, int ic, int id, int ie, typename R>
const typename R::first_argument_type& 
	select_2_5_ab(const typename R::first_argument_type& a,
					const typename R::first_argument_type& b,
					const typename R::first_argument_type& c,
					const typename R::first_argument_type& d,
					const typename R::first_argument_type& e,R r)
{
	compare_strict_or_reflexive<(ic < id), R> cmp;
	if (cmp(d,c,r) ) 
		return select_2_5_ab_cd<ia,ib,id,ic,ie>(a,b,d,c,e,r); // d < c
	return select_2_5_ab_cd<ia,ib,ic,id,ie>(a,b,c,d,e,r); // c <= d
}

template<int ia, int ib, int ic, int id, int ie, typename R>
const typename R::first_argument_type& 
	select_2_5(const typename R::first_argument_type& a,
					const typename R::first_argument_type& b,
					const typename R::first_argument_type& c,
					const typename R::first_argument_type& d,
					const typename R::first_argument_type& e,R r)
{
	compare_strict_or_reflexive<(ia < ib), R> cmp;
	if (cmp(b,a,r) ) 
		return select_2_5_ab<ib,ia,ic,id,ie>(b,a,c,d,e,r); // d < c
	return select_2_5_ab<ia,ib,ic,id,ie>(a,b,c,d,e,r); // d < c
}